#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>

#include <jsoncpp/json/json.h> // 包含json库

using namespace std;

#define SEP " "
#define SEP_LEN strlen(SEP) // 不能使用sizeof()

#define LINE_SEP "\r\n"
#define LINE_SEP_LEN strlen(LINE_SEP) // 不能使用sizeof()

enum
{
    OK = 0,
    DIV_ZERO,
    MOD_ZERO,
    OP_ERROR
};

// "123 + 456" -> "content_len"\r\n"123 + 456"\r\n
string enLength(const string &content)
{
    string send_string = to_string(content.size());
    send_string += LINE_SEP;
    send_string += content;
    send_string += LINE_SEP;

    return send_string;
}

// "content_len"\r\n"123 + 456"\r\n -> "123 + 456"
bool deLength(const string &text, string *content)
{
    auto pos = text.find(LINE_SEP);
    if (pos == string::npos)
        return false;

    string content_len_string = text.substr(0, pos);
    int content_len = stoi(content_len_string);

    *content = text.substr(pos + LINE_SEP_LEN, content_len);
    return true;
}

// "content_len"\r\n"123 + 456"\r\n"content_len"\r\n"123 + 456"\r\n"content_len"\r\n"123 + 456"\r\n
bool ParseOnePackage(string &inbuffer, string *text)
{

    auto pos = inbuffer.find(LINE_SEP);
    if (pos == string::npos)
        return false;

    // 走到这，已经就有了content_len了
    string text_len_string = inbuffer.substr(0, pos);
    int text_len = stoi(text_len_string);

    int total_len = text_len_string.size() + 2 * LINE_SEP_LEN + text_len;

    if (inbuffer.size() < total_len)
    {
        cout << "目前还没读到一个完整报文，请继续！" << endl;
        return false; // 不足一个完整报文
    }

    // 走到这，至少已经有一个完整报文啦！
    *text = inbuffer.substr(0, total_len);

    // 截完之后，清除读走的这个完整报文
    inbuffer.erase(0, total_len);

    return true;
}

class request
{
public:
    request()
        : _x(0), _y(0), _op('0')
    {
    }

    request(int x, int y, char op)
        : _x(x), _y(y), _op(op)
    {
    }

    ~request()
    {
    }

    bool serialize(string *out)
    {
#ifdef MYSELF
        *out = "";
        // out->empty();

        string x_string = to_string(_x);
        string y_string = to_string(_y);

        *out = x_string;
        *out += SEP;
        *out += _op;
        *out += SEP;
        *out += y_string;
#else
        // "123 + 456"
        Json::Value root;
        root["first"] = _x;
        root["second"] = _y;
        root["oper"] = _op;

        // Json::FastWriter writer;
        Json::StyledWriter writer;

        *out = writer.write(root);

#endif
        return true;
    }

    // "xxx op yyy"
    bool deserialize(const string &in)
    {
#ifdef MYSELF
        auto left = in.find(SEP);
        auto right = in.rfind(SEP);

        if (left == string::npos || right == string::npos || left == right)
            return false;
        if (right - (left + SEP_LEN) != 1)
            return false;

        string x_string = in.substr(0, left);
        string y_string = in.substr(right + SEP_LEN);

        if (x_string.empty() || y_string.empty())
            return false;

        _x = stoi(x_string); // _x = atoi(x_string.c_str());
        _op = in.substr(left + SEP_LEN)[0];
        _y = stoi(y_string);
#else
        Json::Value root;
        Json::Reader reader;

        reader.parse(in, root);

        _x = root["first"].asInt();
        _y = root["second"].asInt();
        _op = root["oper"].asInt();

#endif
        return true;
    }

public:
    int _x;
    int _y;
    char _op;
};

class response
{
public:
    response()
        : _exitcode(0), _result(0)
    {
    }

    response(int exitcode, int result)
        : _exitcode(exitcode), _result(result)
    {
    }

    ~response()
    {
    }

    // "exitcode [msg] reslut"
    bool serialize(string *out)
    {
#ifdef MYSELF
        *out = "";

        *out += to_string(_exitcode);
        *out += SEP;
        *out += '[';
        *out += _msg;
        *out += ']';
        *out += SEP;

        *out += to_string(_result);
#else
        Json::Value root;
        root["exitcode"] = _exitcode;
        root["msg"] = _msg;
        root["result"] = _result;

        // Json::FastWriter writer;
        Json::StyledWriter writer;

        *out = writer.write(root);
#endif
        return true;
    }

    // "exitcode [msg] reslut"
    bool deserialize(const string &in)
    {
#ifdef MYSELF
        auto pos = in.find(SEP);
        if (pos == string::npos)
            return false;

        string ec_string = in.substr(0, pos);
        if (ec_string.empty())
            return false;
        _exitcode = stoi(ec_string);

        auto left = in.find("[");
        auto right = in.find("]");
        if (left == string::npos || right == string::npos || left == right)
            return false;

        _msg = in.substr(left + 1, right - left - 1);

        pos = in.rfind(SEP);
        if (pos == string::npos)
            return false;

        string res_string = in.substr(pos + SEP_LEN);
        if (res_string.empty())
            return false;

        _result = stoi(res_string);
#else
        Json::Value root;
        Json::Reader reader;

        reader.parse(in, root);

        _exitcode = root["exitcode"].asInt();
        _msg = root["msg"].asString();
        _result = root["result"].asInt();

#endif
        return true;
    }

public:
    int _exitcode;
    string _msg;
    int _result;
};

// void test()
// {
//     string str = "8 [测试msg] 555";
//     response resp;
//     resp.deserialize(str);
//     cout << resp._exitcode << " [" << resp._msg << "] " << resp._result << endl;
// }